#ifndef BLOQUE_H_INCLUDED
#define BLOQUE_H_INCLUDED

#include "../TiposComunes.h"
#include <string.h>
#include "RegistroVariable.h"

 template <class T> class BloqueRegVar {

private:


    //unsigned int capacidadBloque;
    //unsigned int espacioLibre;
    unsigned char registroActual;
    char * data;
    int size;

    /*
    void inicializarVacio(){
       	this->data = new char[size];
       	this->setCantRegs(0);
       	this->tope = 0;
      }
      */

    //Retorna el último byte ocupado dentro del bloque
	unsigned int getTope() const{
		unsigned int tope = 0;
		for(unsigned char i=0;i<this->getCantRegs();i++){
			tope += this->data[tope+1]+1;
		}
		return tope;
	}

public:
    unsigned int posicionActual;

    void setCantRegs(const unsigned char cant){
    	if (this->data!=NULL)
    		this->data[0]=cant;
    }

    unsigned char getCantRegs() const{
    	if (this->data!=NULL)
    		return this->data[0];
    	else
			return 0;
    }

    //Inicializa un bloque vacío
    //Pre: Ninguna
    //Pos: Cantidad de Registros = 0, PosicionActual dentro del bloque = -1 (no apunta a ningun registro en el blooque)
    BloqueRegVar(int tamanio):size(tamanio) {
    	this->data = new char[size];
        this->setCantRegs(0);
    	this->irAlPrincipio();
    }

    BloqueRegVar():size(512) {
       	this->data = new char[size];
           this->setCantRegs(0);
       	this->irAlPrincipio();
       }

	~BloqueRegVar() {
		if (this->data!= NULL)
			delete [] this->data;
	}
/*
	//Devuelve una referencia al array de datos.
	char  (&getData())[size]{
	    return this->data;
	}
*/

	//Devuelve una referencia al array de datos.
	//retorna una referencia a un puntero constante (permito modificar el contenido del array
	//, pero no apuntar el puntero a otra parte)
	char * const & getrawData() const{
	    return this->data;
	}

	//Forma alternativa de establecer los datos, cuando ya se tiene un buffer creado en memoria.
	void setrawData(  char * const buffer){
		if (this->data!=NULL)
			delete [] this->data;
		this->data = buffer;


	}

	unsigned char cantidadRegistros() const{
		return this->getCantRegs();
	}


	void agregarRegistro(const T &registro, unsigned int tamanio){
		OPERACIONBLOQUE Dummyres;
		this->agregarRegistro(registro,tamanio,Dummyres);
	}

    void agregarRegistro(const T &registro, unsigned int tamanio, OPERACIONBLOQUE & resultado){
    	unsigned int tope = this->getTope();
    	if (size - tope > tamanio ){
    		this->data[tope+1]=tamanio;
			memcpy(&this->data[tope+2],&registro,tamanio);
			this->setCantRegs(this->getCantRegs()+1);
			resultado = EXITO;
    	}
    	else {
    		resultado = FALLA;
    	}

    }

    unsigned char quitarRegistro(const unsigned int posicion){
    	if (this->data!=NULL){
			unsigned char tam=this->data[posicion];

			memcpy(&this->data[posicion],&this->data[posicion+tam+1],size-posicion-tam);

			this->setCantRegs(this->getCantRegs()-1);
			return tam;

    	}
    	return 0;

    }

    void irAlPrincipio(){
    	this->posicionActual=1;
    	this->registroActual=0;
    }

    unsigned char getPosicionActual() const {
    	return this->posicionActual;
    }

    bool siguiente(T& registro){
    	if (this->registroActual < this->getCantRegs()){
    		memcpy(&registro,&this->data[posicionActual+1],this->data[posicionActual]);
    		this->posicionActual += this->data[posicionActual]+1;
    		this->registroActual++;
    		return true;
    	}
    	else
			return false;
    }


};

#endif // BLOQUE_H_INCLUDED
